# -*- coding: utf-8 -*-
from __future__ import unicode_literals
# Create your views here.
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView

from oauth.models import OAuthQQUser, OAuthSinaUser
from oauth.serializers import OauthQQUserSerializer, OAuthSinaUserSerializer

"""
对于应用而言，需要进行两步：
1. 获取Authorization Code；        其实就是通过 url来得到用户的同意
2. 通过Authorization Code获取Access Token
对于我们来说,
3.通过token 换取openid
https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id=101474184&redirect_uri=http://www.meiduo.site:8080/oauth_callback.html&state=test
一.分析需求
    当用户点击qq登陆按钮的时候,发送一个请求就可以,后端返回我们一个url

二.步骤(大概的思路)
    根据qq提供的接口文档 拼接url

三.确定请求方式和路由
    GET
四.选取哪个视图(结合需求,使用排除法)
五.编码
"""
from QQLoginTool.QQtool import OAuthQQ
from mall import settings
from oauth.utils import generate_openid_token
from oauth.utils import check_access_token
"""
QQ登陆就接口而言,只有两个
1.给用户返回 QQ的登陆页面
2.拿到 access_token 去获取openid
"""


# 返回登陆网址的类视图
class OOAuthQQURLAPIView(APIView):
    def get(self, request):
        # 创建OAuthQQ的实例对象
        state = request.query_params.get('state')
        print('state:', state)
        if state is None:
            state = '/'
        oauth = OAuthQQ(
            client_id=settings.QQ_CLIENT_ID,
            client_secret=settings.QQ_CLIENT_SECRET,
            redirect_uri=settings.QQ_REDIRECT_URI,
            state=state)
        # 调用实例对象的方法
        auth_url = oauth.get_qq_url()
        return Response({'auth_url': auth_url})


"""
一,需求:
    当用户点击同意之后,qq认证服务器会返回一个code,这个时候,需要让前端将
    code返回给后端

二.思路(步骤)

    1.接收code
    2.通过code换取token
    3.通过token换取openid

    4. 如果用户绑定过,则直接登陆
         如果用户没绑定过,则绑定


三. 请求方式和路由
    GET     /oauth/qq/users/?code=xxxx

    POST    /oauth/qq/users/        body code:xxxx
四. 确定选择哪个视图
    APIView:
    GenericAPIView:
    ListAPIVIew,RetrieveAPIView:

"""

# 用来获取 用户 openid 的类视图
"""
接受参数[要进行校验]
通过code换token
用token换openid
根据openid来判断是否已经绑定过
没查询出来,说明未绑定,则进行绑定
[如何绑定?弹出绑定页面,绑定页面属于敏感信息,不应该一直有效,要设置有效期]
查询出来,说明已经绑定,直接登陆
[如何实现直接登陆?直接后端直接生成token给前端,前端每次请求带上token]
"""


class OauthQQUserAPIView(APIView):
    def get(self, request):
        code = request.query_params.get('code')
        if code is None:
            return Response(status=status.HTTP_400_BAD_REQUEST)
        # 先获取实例信息
        oauth = OAuthQQ(
            client_id=settings.QQ_CLIENT_ID,
            client_secret=settings.QQ_CLIENT_SECRET,
            redirect_uri=settings.QQ_REDIRECT_URI,
        )
        # 获取用户的 openid
        try:
            token = oauth.get_access_token(code)
            openid = oauth.get_open_id(token)
        except Exception as e:
            return Response(status=status.HTTP_400_BAD_REQUEST)

        # 在 oauth 模型类里面查询 是否有 openid,查询到了,抛出异常
        try:
            user = OAuthQQUser.objects.get(openid=openid)
        except OAuthQQUser.DoesNotExist:
            # 如果没查询出来，则说明没绑定过，进行绑定
            # 绑定界面　不应该一直有效，要设置有效期
            # 使用 itsdangerous 进行加密,调用oauth下 utils 里面封装的　itsdangerous　序列化器
            openid_itsdangerous = generate_openid_token(openid)
            return Response({'access_token': openid_itsdangerous})
        else:
            # 没有异常的时候
            # 如果查询出来，说明绑定过，直接进行登陆
            from rest_framework_jwt.settings import api_settings
            jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
            jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER

            payload = jwt_payload_handler(user.user)
            token = jwt_encode_handler(payload)

            return Response({'token': token,
                             'username': user.user.username,
                             'user_id': user.user.id
                             })

    def post(self, request):
        # 接受数据
        data = request.data
        # 校验数据
        serializer = OauthQQUserSerializer(data=data)
        serializer.is_valid(raise_exception=True)
        # 保存用户信息和 openid
        qq_user = serializer.save()

        # 绑定 完成后　要进行自动登陆　[此部分代码要进行抽取]
        from rest_framework_jwt.settings import api_settings
        jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
        jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER

        payload = jwt_payload_handler(qq_user.user)
        token = jwt_encode_handler(payload)

        return Response({'token': token,
                         'username': qq_user.user.username,
                         'user_id': qq_user.user.id
                         })


# 绑定用户的类视图
"""
用户点击绑定的时候，前端要将　
openid,手机号,密码,短信验证码　提交后端
接收数据
校验数据[序列化器进行校验]
将用户信息和　openid  进行保存
返回响应
私密数据 POST 　　oauth/qq/user
"""


from mall import settings
from itsdangerous import TimedJSONWebSignatureSerializer as Seralizer

s = Seralizer(secret_key=settings.SECRET_KEY,expires_in=60*60)

# 模拟数据？？？
data = {
    'openid': '1234567890'
}
# 对数据加密
token = s.dumps(data)
# 解密
s = Seralizer(secret_key=settings.SECRET_KEY,expires_in=60*60)
s.loads(token)

# 如果　token 被修改了，过期了，都能被检测出来？
s = Seralizer(secret_key=settings.SECRET_KEY,expires_in=60*60)
data = {
    'openid': '1234567890'
}
token = s.dumps(data)




"""
新浪微博第三方登陆 接口
两部分: 1.返回登陆页面
       2.用户授权后,获取 access_token
       [POST    /oauth/qq/users/        body code:xxxx]
       3.判断用户是否绑定?
        未注册用户直接进行注册
        已注册用户直接绑定 access_token

"""

from mall import settings
from libs.weibo import sina_oauth


# 获取 回调网址类视图
class OAuthSinaURLAPIView(APIView):
    def get(self, request):
        state = request.query_params.get('state')
        print('state:', state)
        if state is None:
            state = '/'
        client = sina_oauth.APIClient(
            app_key=settings.WEIBO_APP_KEY,
            app_secret=settings.WEIBO_APP_SECRET,
            redirect_uri=settings.WEIBO_CALLBACK_URL,
            state=state
            )
        url = client.get_authorize_url()
        return Response({'weibo_url': url})


# 获取 access_token 类视图

class OAuthSinaUserAPIView(APIView):
    # 从前端 获取 code,用 code获取 access_token[敏感信息要加密],判断　access_token　是否存在
    def get(self, request):
        code = request.query_params.get('code')
        if code is None:
            return Response(status=status.HTTP_400_BAD_REQUEST)
        # 通过 code 获取 access_token

        client = sina_oauth.APIClient(
            app_key=settings.WEIBO_APP_KEY, app_secret=settings.WEIBO_APP_SECRET,
            redirect_uri=settings.WEIBO_CALLBACK_URL)
        oauth = client.request_access_token(code)
        try:
            token1 = oauth.get('access_token')
        except Exception as e:
            return Response(status=status.HTTP_400_BAD_REQUEST)
        # tocken 里面存储了　access_token
        # 根据 access_token 进行查询
        try:
            sina_user = OAuthSinaUser.objects.get(access_token=token1)
        except OAuthSinaUser.DoesNotExist:
            # 如果没查询出来,则说明没绑定过,则绑定

            # 1. access_token属于一个敏感信息,
            # 2. 绑定界面 不应该一直有效,应该设置一个有效期

            access_token_itsdangerous = generate_openid_token(token1)
            print('access_token_itsdangerous:',access_token_itsdangerous)

            return Response({'access_token': access_token_itsdangerous})


        else:
            # 没有异常的时候
            # 如果查询出来,则说明绑定过,则登陆

            from rest_framework_jwt.settings import api_settings

            jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
            jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER

            payload = jwt_payload_handler(sina_user.user)
            token1 = jwt_encode_handler(payload)

            return Response({'token': token1,
                             'username': sina_user.user.username,
                             'user_id': sina_user.user.id
                             })

    # 使用序列化器　保存　用户信息,绑定完成后自动登录
    def post(self, request):
        # 接受数据
        data = request.data
        # 校验数据
        serializer = OAuthSinaUserSerializer(data=data)
        serializer.is_valid(raise_exception=True)
        # 保存用户信息和 openid
        sina_user = serializer.save()

        # 绑定 完成后　要进行自动登陆　[此部分代码要进行抽取]
        from rest_framework_jwt.settings import api_settings
        jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
        jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER

        payload = jwt_payload_handler(sina_user.user)
        token = jwt_encode_handler(payload)

        return Response({'access_token': token,
                         'username': sina_user.user.username,
                         'user_id': sina_user.user.id
                         })

# 绑定用户
from mall import settings
from itsdangerous import TimedJSONWebSignatureSerializer as Seralizer

s = Seralizer(secret_key=settings.SECRET_KEY,expires_in=60*60)

# 模拟数据？？？
data = {
    'openid': '1234567890'
}
# 对数据加密
access_token = s.dumps(data)
# 解密
s = Seralizer(secret_key=settings.SECRET_KEY, expires_in=60*60)
s.loads(access_token)

s = Seralizer(secret_key=settings.SECRET_KEY, expires_in=60*60)
data = {
    'openid': '1234567890'
}
access_token = s.dumps(data)









